/*
 *  Copyright (C) 2004 Cidero, Inc.
 *
 *  Permission is hereby granted to any person obtaining a copy of 
 *  this software to use, copy, modify, merge, publish, and distribute
 *  the software for any non-commercial purpose, subject to the
 *  following conditions:
 *  
 *  The above copyright notice and this permission notice shall be included
 *  in all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 
 *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
 *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY IN CONNECTION WITH THE SOFTWARE.
 * 
 *  File: $RCSfile: PrismiqAgentReadThread.java,v $
 *
 */

package com.cidero.bridge.prismiq;

import java.io.*;
import java.net.*;
import java.util.logging.Logger;

import com.cidero.util.SynchronizedQueue;

/**
 * Thread to reading incoming messages from the PRISMIQ 'magent' TCP port
 * Most incoming messages are responses to requests sent to the port by
 * the main thread, but there are also asynchonous messages containing
 * Prismiq state information. This thread forwards the request responses
 * to the main thread via a FIFO-queue, and invokes a separate notify 
 * listener for the asynchronous messages
 *
 * Cmd responses
 *
 *  Basic syntax is:
 *
 *    <responseCode> [seqNum] <responseCodeText> <responseBody>
 *
 *  GET AUDIO_VOLUME response example:
 *
 *    261 [1] OK value= "95"
 *  
 *
 * Asynchronous messages
 *
 *  The Prismiq outputs a set of asynchronous messages on the media agent
 *  TCP connection. This listener interface allows them to be acted upon.
 *
 *  The message codes are:
 *
 *   902       Stream stopped message
 *   905       Automatic timestamp/PTS messages
 *   907/908   Notify on new Shoutcast song/title
 *   909       Notify when media length known
 *   910/911   Notify on audio/video underflow
 *   912       Notify on invalid audio data
 *    
 *   Note that additional text follows the message code. See Prismiq
 *   media agent doc for more details
 *
 *   Sample msg:   "910 Audio underflow"
 * 
 */
public class PrismiqAgentReadThread implements Runnable
{
  private static Logger logger = 
    Logger.getLogger("com.cidero.bridge.prismiq");

  Socket socket = null;
  SynchronizedQueue queue;
  long timeStampCount = 0;
  PrismiqMediaRenderer mediaRenderer;
  

  /**
   * Constructor
   */
  public PrismiqAgentReadThread( PrismiqMediaRenderer mediaRenderer,
                                 Socket socket, SynchronizedQueue queue )
  {
    this.mediaRenderer = mediaRenderer;
    this.socket = socket;
    this.queue = queue;
  }
  
  private Thread readerThread = null;  // for clean shutdown via stop()
  
  /**
   * Thread run method
   */
  public void run()
  {
    logger.fine("PrismiqAgentReadThread: Running...");

    Thread thisThread = Thread.currentThread();
    
    PrismiqStateModel prismiqStateModel = mediaRenderer.getStateModel();

    BufferedReader reader;

    try 
    {
      reader = new BufferedReader( 
                    new InputStreamReader( socket.getInputStream() ) );
    }
    catch( Exception e )
    {
      logger.fine( "Error opening TCP socket for input" + e );
      return;
    }

    while( readerThread == thisThread )
    {
      //
      // Read lines one at a time, passing messages back to main thread
      // On error terminate read thread
      //
      try 
      {
        String responseLine = reader.readLine();
        
        //
        // If this is a response to a command, forward it to the
        // command thread. Asynchronous notifications (codes 900-999)
        // are handled separately
        //
        if( responseLine.startsWith("9") )
        {
          prismiqStateModel.parseNotifyMsg( responseLine );
          prismiqStateModel.notifyObservers();
        }
        else
        {
          //logger.fine("Response: " + responseLine );
          if( ! queue.add( responseLine, 2000 ) )
            logger.fine("PrismiqAgentReadThread: dropping response");
        }
      }
      catch( Exception e )
      {
        logger.fine("PrismiqAgentReadThread: Error: " + e );
        return;
      }
    }
    
    logger.fine("PrismiqAgentReadThread: Shutting down...");
  }

  public void start()
  {
    readerThread = new Thread( this );
    readerThread.start();
  }
  
  public void stop()
  {
    readerThread = null;
  }
  
  
}
